float4x4 World, Projection, View;

struct PS_INPUT
{
	float4 Pos : SV_POSITION;
	float4 Colour : COLOR;
};

struct VS_INPUT
{
	float4 Pos : POSITION;
	float4 Colour : COLOR;
};

// vertex shader
PS_INPUT VS(VS_INPUT input)
{
	PS_INPUT output;
	output.Pos = mul(input.Pos, World);
	output.Pos = mul(output.Pos, View);
	output.Pos = mul(output.Pos, Projection);
	output.Colour = input.Colour;

	return output;
}

// pixel shader
float4 PS(PS_INPUT input) : SV_Target
{
	return input.Colour;
}

// technique
technique10 main
{
	pass P0
	{
		SetVertexShader( CompileShader( vs_4_0, VS() ) );
        SetGeometryShader( NULL );
        SetPixelShader( CompileShader( ps_4_0, PS() ) );
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Texture2D DiffuseMap;

float3 CameraPosition;
float3 LightDirection = {0.0f, 0.0f, 1.0f};

// Material
float4 Ka;
float4 Kd;
float4 Ks;
float SpecularPower;

SamplerState TextureSampler
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};


struct VS_INPUT2
{
    float4 position : POSITION;
    float2 tex : TEXCOORD0;
	float3 normal : NORMAL;
};

struct PS_INPUT2
{
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
   	float3 normal : NORMAL;
	float3 viewDirection : TEXCOORD1;
};

PS_INPUT2 meshVS(VS_INPUT2 input)
{
    PS_INPUT2 output;
	float4 worldPosition;

    
	// Change the position vector to be 4 units for proper matrix calculations.
    input.position.w = 1.0f;

	// Calculate the position of the vertex against the world, view, and projection matrices.
    output.position = mul(input.position, World);
    output.position = mul(output.position, View);
    output.position = mul(output.position, Projection);
    
	// Store the texture coordinates for the pixel shader.
    output.tex = input.tex;
    
	// Calculate the normal vector against the world matrix only.
	output.normal = mul(input.normal, (float3x3)World);
	
	// Normalize the normal vector.
	output.normal = normalize(output.normal);

	// Calculate the position of the vertex5 in the world.
	worldPosition = mul(input.position, World);

	// Determine the viewing direction based on the position of the camera and the position of the vertex in the world.
	output.viewDirection = CameraPosition.xyz - worldPosition.xyz;
	
	// Normalize the viewing direction vector.
	output.viewDirection = normalize(output.viewDirection);

	return output;
}


float4 meshPS(PS_INPUT2 input) : SV_Target
{
	float4 textureColor;
	float4 color;
	float3 lightDir;
	float lightIntensity;
	float3 reflection;
	float4 specular;

	textureColor = DiffuseMap.Sample(TextureSampler, input.tex);
	color = Ka;
	
	lightDir = -LightDirection;

	lightIntensity = saturate(dot(input.normal, lightDir));
	
	if(lightIntensity > 0.0f)
	{
		// Determine the final diffuse color based on the diffuse color and the amount of light intensity.
		color += (Kd * lightIntensity);

		// Add the specular component to the output color and saturate it.
		color = saturate(color);

		// Calculate the reflection vector based on the light intensity, normal vector, and light direction.
		reflection = normalize(2 * lightIntensity * input.normal - lightDir); 

		// Determine the amount of specular light based on the reflection vector, viewing direction, and specular power.
		specular = pow(saturate(dot(reflection, input.viewDirection)), SpecularPower);
	}
	
	// Multiply the texture pixel and the input color to get the textured result.
	color = color * textureColor;
	
	// Add the specular component last to the output color.
	color = saturate(color + specular);
	
	return color;
}


technique10 Default
{
    pass pass0
    {
        SetVertexShader(CompileShader(vs_4_0, meshVS()));
        SetPixelShader(CompileShader(ps_4_0, meshPS()));
        SetGeometryShader(NULL);
    }
}